/*
 * $Id: SignalAgent.cc,v 1.3 2005-06-28 15:23:58 bacon Exp $
 */

#include <xpp/bas/SignalAgent.h>
#include <xp/bas/assert.h>

namespace xpp
{
	namespace bas
	{

		SignalAgent* SignalAgent::instance = XP_NULL;
		
		SignalAgent::SignalAgent ()
		{
			//
			// WARNING: Each application should have only one 
			//          instance of SignalAgent.
			//
			xp_assert (SignalAgent::instance == XP_NULL);
			SignalAgent::instance = this;
		
			for (xp_size_t i = 0; i < xp_countof(mask); i++) mask[i] = 0;
		}

		SignalAgent::~SignalAgent ()
		{
			SignalAgent::instance = XP_NULL;
		}
		
		int SignalAgent::ignoreSignal (int sig)
		{
			if (sig >= NSIG) return -1;
			mask[sig] = 1;
			if (xp_signal (sig, SIG_IGN) == SIG_ERR) return -1;
			return 0;
		}

		int SignalAgent::defaultifySignal (int sig)
		{
			if (sig >= NSIG) return -1;
			mask[sig] = 2;
			if (xp_signal (sig, SIG_DFL) == SIG_ERR) return -1;
			return 0;
		}

		int SignalAgent::manageSignal (int sig)
		{
			if (sig >= NSIG) return -1;
			mask[sig] = 3;
			if (xp_signal(sig, perform_proc) == SIG_ERR) return -1;
			return 0;
		}
		
		int SignalAgent::ignoreAllSignals ()
		{
			int r = 0;
			for (int i = 0; i < NSIG; i++) {
				if (ignoreSignal(i) == -1) r = -1;
			}
			return r;
		}

		int SignalAgent::defaultifyAllSignals ()
		{
			int r = 0;
			for (int i = 0; i < NSIG; i++) {
				if (defaultifySignal(i) == -1) r = -1;
			}
			return r;
		}

		int SignalAgent::manageAllSignals ()
		{
			int r = 0;
			for (int i = 0; i < NSIG; i++) 
				if (manageSignal(i) == -1) r = -1;
			return r;
		}

		int SignalAgent::reapplyAllSigActions ()
		{
			int r = 0;

			for (int i = 0; i < NSIG; i++) {
				if (mask[i] == 0) /* do nothing */ ;
				else if (mask[i] == 1) {
					if (xp_signal(i, SIG_IGN) == SIG_ERR) r = -1;
				}
				else if (mask[i] == 2) {
					if (xp_signal(i, SIG_DFL) == SIG_ERR) r = -1;
				}
				else {
					if (xp_signal(i, perform_proc) == SIG_ERR) r = -1;
				}
			}

			return r;
		}
		
		void SignalAgent::perform_proc (int sig)
		{
			xp_signal (sig, SIG_IGN);
			SignalAgent::instance->perform_proc_two (sig);
			xp_signal (sig, SignalAgent::perform_proc);
		}

		void SignalAgent::perform_proc_two (int sig)
		{
			xp_assert (mask[sig] != 0 && mask[sig] != 1 && mask[sig] != 2);
			handleSignal (sig);
		}
		
	}
}
